package cn.kailangtu.commontools.socket;

import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

public class SocketClient {
    private static final String TAG = "SocketClient";
    private static final int HEARTBEAT_INTERVAL = 30000; // 30秒心跳
    private static final int RECONNECT_DELAY = 5000;    // 5秒重连间隔

    private final String host;
    private final int port;
    private volatile boolean isConnected = false;
    private volatile boolean shouldReconnect = true;

    private Socket socket;
    private OutputStream outputStream;
    private InputStream inputStream;
    private final ExecutorService executor = Executors.newFixedThreadPool(3);
    private final LinkedBlockingQueue<byte[]> sendQueue = new LinkedBlockingQueue<>();
    private final Handler mainHandler = new Handler(Looper.getMainLooper());

    private long lastReveiveTime = 0;

    // 状态监听接口
    public interface SocketListener {
        void onMessageReceived(byte[] data);
        void onStatusChanged(boolean isConnected);
    }

    private SocketListener listener;

    public SocketClient(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public void setSocketListener(SocketListener listener) {
        this.listener = listener;
    }

    public void connect() {
        shouldReconnect = true;
        executor.execute(this::connectTask);
    }

    private void connectTask() {
        try {
            closeConnection();
            socket = new Socket(host, port);
            socket.setKeepAlive(true);
            outputStream = socket.getOutputStream();
            inputStream = socket.getInputStream();

            updateConnectionStatus(true);
           // startHeartbeat();
            startReceiveThread();
            startSendThread();

        } catch (IOException e) {
            handleDisconnect(e);
        }
    }

    private void startReceiveThread() {
        executor.execute(() -> {
            byte[] buffer = new byte[2048];
            while (isConnected) {
                try {
                    int length = inputStream.read(buffer);
                    if (length > 0) {
                        lastReveiveTime = System.currentTimeMillis();
                        byte[] data = new byte[length];
                        System.arraycopy(buffer, 0, data, 0, length);

                        notifyMessageReceived(data);
                    }
                } catch (IOException e) {
                    handleDisconnect(e);
                    break;
                }
            }
        });
    }

    private void startSendThread() {
        executor.execute(() -> {
            while (isConnected) {
                try {
                    byte[] data = sendQueue.take();
                    outputStream.write(data);
                    outputStream.flush();
                } catch (IOException e) {
                    handleDisconnect(e);
                } catch (InterruptedException ignored) {
                }
            }
        });
    }

    private void startHeartbeat() {
        executor.execute(() -> {
            while (isConnected) {
                try {
                    Thread.sleep(HEARTBEAT_INTERVAL);
                    sendData("heartbeat".getBytes());
                } catch (InterruptedException e) {
                    break;
                }
            }
        });
    }

    public void sendData(byte[] data) {
        if (isConnected) {
            sendQueue.offer(data);
        }
    }

    private void handleDisconnect(Exception e) {
        updateConnectionStatus(false);
        if (shouldReconnect) {
            scheduleReconnect();
        }
    }

    private void scheduleReconnect() {
        mainHandler.postDelayed(this::connect, RECONNECT_DELAY);
    }

    private void updateConnectionStatus(final boolean connected) {
        isConnected = connected;
            if (listener != null) {
                listener.onStatusChanged(connected);
            }
    }

    private void notifyMessageReceived(final byte[] data) {

            if (listener != null) {
                listener.onMessageReceived(data);
            }
    }

    public void disconnect() {
        shouldReconnect = false;
        closeConnection();
    }

    private void closeConnection() {
        try {
            if (socket != null) {
                socket.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
            if (inputStream != null) {
                inputStream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        updateConnectionStatus(false);
    }
}